import random
import math
#对一个标签的定义
class BaseTag():
    def __init__(self):
        self.transmit_time=None
        self.id = self._generate_uid()
    def generate_time(self, min_t=None, max_t=None):
        '''
        Generate the time at which the sensor transmits to the reader
            Parameters:
                max (int): the max time. Default=None
                min (int): the min time. Default=None
            Returns:
                time (int): the time at which the sensor transmits
        '''
        if min_t is None:
            min_t=0
        
        if max_t is None:
            max_t=min_t+10
            
            self.transmit_time = random.randrange(min_t, max_t)

        return self.transmit_time
        
    def _generate_uid(self, length=64):
        return "".join([str(random.randint(0, 1)) for _ in range(length)])
    
    def __str__(self) -> str:
        return self.id
    
    def __repr__(self) -> str:
        return self.__str__()

'''支持ALOHA标签
 1. 重传机制：当发生碰撞时，标签需要重新选择一个时间进行重传。
 2. 记录重传次数：避免无限重传，通常有最大重传次数限制。
 3. 退避策略：比如指数退避，在碰撞后等待随机时间再重传。
 4. 状态标记：如是否已经成功传输。
纯aloha是连续时间的没有调试成功，放弃
 '''
class PureAlohaTag(BaseTag):
    def __init__(self, max_retries=5, backoff_factor=2.0, frame_length=1.0):
        """
        初始化ALOHA标签
        参数:
            max_retries: 最大重试次数 (默认5)
            backoff_factor: 退避因子 (默认2.0)
            frame_length: 数据帧长度/传输时长 (默认1.0)
        """
        super().__init__()
        self.max_retries = max_retries
        self.backoff_factor = backoff_factor
        self.frame_length = frame_length  # 数据帧传输所需时间
        self.retry_count = 0
        self.successful = False
        self.active = True
        self.transmit_end = None  # 传输结束时间
    
    
    def handle_collision(self, collision_time):
        """
        处理碰撞事件：执行退避策略并更新传输时间
        参数:
            collision_time: 碰撞发生的时间
        返回:
            bool: 是否成功安排重传
        """
        if self.retry_count >= self.max_retries:
            self.active = False
            return False
        
        self.retry_count += 1
        
        # 指数退避算法：退避时间随重试次数增加
        backoff = random.expovariate(self.backoff_factor) * (2 ** self.retry_count)
        new_start = collision_time + backoff
        
        # 更新传输时间
        self.transmit_time = new_start
        self.transmit_end = new_start + self.frame_length
        return True
    
    def mark_success(self):
        """标记标签已成功传输"""
        self.successful = True
        self.active = False
    
    def is_transmitting(self, current_time):
        """
        检查标签是否在当前时间传输
        参数:
            current_time: 当前仿真时间
        返回:
            bool: 是否正在传输
        """
        if not self.active or self.successful:
            return False
            
        # 检查当前时间是否在传输时间段内
        return self.transmit_time <= current_time <= self.transmit_end
    
    def reset(self):
        """重置标签状态（用于多次实验），保持ID不变"""
        self.transmit_time = None
        self.transmit_end = None
        self.retry_count = 0
        self.successful = False
        self.active = True
    
    def __str__(self):
        status = "成功" if self.successful else f"重试:{self.retry_count}"
        return f"ALOHA标签(ID={self.id[:8]}..., 开始={self.transmit_time:.2f}, 结束={self.transmit_end:.2f}, {status})"
    
class FrameSlottedAlohaTag(BaseTag):
    def __init__(self):
        super().__init__()
        self.active = True
        self.success = False
        self.selected_slot = 0
        self.retry_count = 0   
        self.max_retries = 10  #暂时设定最大重传次数为10    
    
    def select_slot(self,frame_size):
        #选择[0,frame_size-1]帧的时隙
        #该函数在阅读器发出命令后在阅读器内部执行,自己猜测
        self.selected_slot = random.randint(0, frame_size - 1)
        return self.selected_slot
    
    def handle_collision(self):
        # 发生碰撞后，增加重试次数，如果超过最大重试次数，则标记为失败
        # 发生碰撞后，需要根据阅读器的指令，重新选择下一帧数据的时隙，这里没有实现，暂时保留疑问
        self.retry_count += 1
        if self.retry_count >= self.max_retries:
            self.active = False
            return False
        return True
    
    def mark_success(self):
        self.successful = True
        self.active = False
    
    def __str__(self):
        status = "成功" if self.successful else f"重试:{self.retry_count}"
        slot_info = f"时隙:{self.selected_slot}" if self.selected_slot is not None else "未选时隙"
        return f"帧时隙标签(ID={self.id[:8]}..., {slot_info}, {status})"
    
    def reset(self):
        self.retry_count = 0
        self.successful = False
        self.active = True
        self.selected_slot = None
    
    